package com.koron.common.core.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.*;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.GZIPInputStream;

/**
 * User: pan
 * Date: 2019/9/12
 * Description: No Description
 */
@Slf4j
public class HttpClient {

    private RestTemplate template = new RestTemplate();

    private CloseableHttpClient httpclient = HttpClients.createDefault();

    public String doGet(String url, Map<String, String> params) {
        if (params == null) {
            return null;
        }
        if (params.size() == 0) {
            return doGet(url);
        }
        StringBuffer sb = new StringBuffer(url).append("?");
        Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        url = sb.substring(0, sb.length() - 1);
        log.info("doGet请求:{}",url);
        return doGet(url);
    }


    public String doGet(String url) {
        return template.getForObject(url, String.class);
    }

    /**
     * post请求(body)
     *
     * @param url
     * @param body
     * @return
     */
    public String doPost(String url, String body) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> request = new HttpEntity<>(body, headers);
        return template.postForObject(url, request, String.class);
    }

    /**
     * post请求(params)
     *
     * @param url
     * @param params
     * @return
     */
    public String doPost(String url, Map<String, String> params) {
        Assert.isTrue(params != null && params.size() > 0, "参数不合法");
        HttpHeaders headers = new HttpHeaders();
        HttpMethod method = HttpMethod.POST;
        // 以表单的方式提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> queryMap = new LinkedMultiValueMap<>();
        Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            queryMap.add(entry.getKey(), entry.getValue());
        }
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(queryMap, headers);
        return template.exchange(url, method, request, String.class).getBody();
    }

    public String doPost(String httpUrl, Map<String, String> header, byte[] body) {
        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpUrl);
            // 通过远程url连接对象打开连接
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接请求方式
            connection.setRequestMethod("POST");
            // 设置连接主机服务器超时时间：2000毫秒
            connection.setConnectTimeout(2000);
            // 设置读取主机服务器返回数据超时时间：60000毫秒
            connection.setReadTimeout(60000);

            // 默认值为：false，当向远程服务器传送数据/写数据时，需要设置为true
            connection.setDoOutput(true);
            // 默认值为：true，当前向远程服务读取数据时，设置为true，该参数可有可无
            connection.setDoInput(true);

            connection.setRequestProperty("Content-Type", "application/octet-stream");

            for (Map.Entry<String, String> entry : header.entrySet()) {
                connection.setRequestProperty(entry.getKey(), entry.getValue());
            }

            // 通过连接对象获取一个输出流
            os = connection.getOutputStream();
            // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的
            os.write(body);
            // 通过连接对象获取一个输入流，向远程读取
            if (connection.getResponseCode() == 200) {

                is = connection.getInputStream();
                // 对输入流对象进行包装:charset根据工作项目组的要求来设置
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

                StringBuffer sbf = new StringBuffer();
                String temp = null;
                // 循环遍历一行一行读取数据
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            } else {
                log.warn("http code:{}, connection.getResponseCode()");
            }
        } catch (MalformedURLException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            // 断开与远程地址url的连接
            connection.disconnect();
        }
        return result;
    }

    /**
     * 下载文件到指定文件
     *
     * @param url
     * @param path 文件的具体路径
     * @return
     */
    public boolean download(String url, String path) {
        try {
            byte[] bytes = download(url);
            FileUtils.writeByteArrayToFile(new File(path), bytes);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 下载文件
     *
     * @param url
     * @return
     */
    public byte[] download(String url) {
        HttpGet httpGet = new HttpGet(url);
        url = handleUrl(url);
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763");
        byte[] result = null;
        try (CloseableHttpResponse response = httpclient.execute(httpGet)) {
            org.apache.http.HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = entity.getContent();
                ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
                byte[] buff = new byte[1024];
                int line = 0;
                while ((line = inputStream.read(buff)) != -1) {
                    swapStream.write(buff, 0, line);
                }
                result = swapStream.toByteArray();
                inputStream.close();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }

    private String handleUrl(String url) {
        String[] urlArray = StringUtils.split(url, "?", 2);
        String[] params = StringUtils.split(urlArray[1], "&");
        Map<String, String> encodeParams = new HashMap<>();
        try {
            for (String p : params) {
                String[] kv = StringUtils.split(p, "=");
                encodeParams.put(kv[0], URLEncoder.encode(kv[1], "UTF-8"));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        Iterator<Map.Entry<String, String>> iterator = encodeParams.entrySet().iterator();
        StringBuffer paramStr = new StringBuffer(urlArray[0]);
        if (!MapUtils.isEmpty(encodeParams)) {
            paramStr.append("?");
        }
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            paramStr.append(entry.getKey()).append("=").append(entry.getValue());
            if (iterator.hasNext()) {
                paramStr.append("&");
            }
        }
        return paramStr.toString();
    }

    /**
     * 下载
     * @param response
     * @param file
     * @throws Exception
     */
    public static void downLoadCommon(HttpServletResponse response, File file, String filename) throws Exception {
        filename = new String(filename.getBytes("utf-8"),"ISO8859-1");
        response.setContentType("text/html;charset=utf-8");
        // response设置Content-Disposition
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        FileInputStream fis = new FileInputStream(file);
        byte[] buff = new byte[2048];
        int len = 0;
        OutputStream os = response.getOutputStream();
        while ((len = fis.read(buff)) > 0) {
            os.write(buff, 0, len);
        }
        os.close();
        fis.close();
    }



    /**
     * 请求接口公共方法
     *
     * @param Methods
     * @param url
     * @param UrlParams
     * @return
     */
    public static String getResponse(String url, HttpMethod Methods, Map<String, String> UrlParams, Map<String, String> HeaderParams) throws IOException {
        RestTemplate client = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        HttpMethod method = Methods;
        // 以表单的方式提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 设置用户提交的header头数据
        if (!HeaderParams.isEmpty()) {
            HeaderParams.forEach((k, v) -> {
                headers.set(k, v);
            });
        }
        // 将请求头部和参数合成一个请求
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        if (Methods == HttpMethod.GET) {
            String _UrlParams = getUrlParamsByMap(UrlParams);
            url = url + "?" + _UrlParams;
        } else {
            if (!UrlParams.isEmpty()) {
                UrlParams.forEach((k, v) -> {
                    params.put(k, Collections.singletonList(v));
                });
            }
        }
        log.info("URL:{}", url);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
        // 执行HTTP请求，将返回的结构使用spring ResponseEntity处理http响应
        ResponseEntity<byte[]> responseEntity = client.exchange(url, method, requestEntity, byte[].class);
        String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);
        // gzip编码
        if ("gzip".equals(contentEncoding)) {
            // gzip解压服务器的响应体
            byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));
//            logger.info(new String(data, StandardCharsets.UTF_8));
            return new String(data);
        } else {
            // 其他编码暂时不做处理(如果需要处理其他编码请自行扩展)
            return new String(responseEntity.getBody());
        }
    }

    /**
     * Gzip解压缩
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] unGZip(InputStream inputStream) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
            byte[] buf = new byte[4096];
            int len = -1;
            while ((len = gzipInputStream.read(buf, 0, buf.length)) != -1) {
                byteArrayOutputStream.write(buf, 0, len);
            }
            return byteArrayOutputStream.toByteArray();
        } finally {
            byteArrayOutputStream.close();
        }
    }

    /**
     * 　　* 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * 　　* @param params 需要排序并参与字符拼接的参数组
     * 　　* @return 拼接后字符串
     * 　　* @throws UnsupportedEncodingException
     *
     */
    public static String getUrlParamsByMap(Map<String, String> params) throws UnsupportedEncodingException {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            value = URLEncoder.encode(value, "UTF-8");
            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }








}
